/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab-modules.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_TetraMesh_ModelStructure_h__
#define __dylab_TetraMesh_ModelStructure_h__

//===========================================================================================
#include <dylab/utils/ArrayList.h>
#include <dylab/utils/geometry/Vector3.h>
#include <dylab/simobject/ComModelStructure.h>

//===========================================================================================
namespace dylab {

    /**
     * The structure primarily intendet for dynamic deformable simulation object.     
     */
    class TetraMesh_ModelStructure 
        : public ComModelStructure
        , public ComModelStructure::IMassPoints
        , public ComModelStructure::ITetrahedralVolume
        , public ComModelStructure::IBoundaryMesh
    {
    public:
        // vertex, edge, half-face and tetra identifier types
		typedef MassPoint::id_t nodeid_t;
        typedef uint32_t hfaceid_t;
		typedef Tetrahedron::id_t tetraid_t;
    public:
        ///
        static const String COMPONENT_NAME;
    public:
        //-----------------------------------------------------------------------------
        ///
        class NodeTraits 
            : public MassPoint
        {
        private:
            uint32_t mRefs;
        public:
            void resetRefs() { mRefs = 0; }
            bool testRefs()  { return mRefs == 0; }
            void incRefs()   { mRefs++; }
            void decRefs()   { mRefs--; }
        };
        //-----------------------------------------------------------------------------
        /// boundery vertex
        class Vertex : public IBoundaryMesh::Vertex
        {
        private:
            ///
            nodeid_t mReferencedNodeID;
        public:
            /**
             */
            Vertex(nodeid_t _refNodeID, uint32_t _index, const Vector3 & _position, const Vector3 & _normal, real_t _u, real_t _v)
                : IBoundaryMesh::Vertex(_index, _position, _normal, _u, _v), mReferencedNodeID(_refNodeID)
                    { }
            /**
             */
            nodeid_t getReferencedNodeID() const
                    { return mReferencedNodeID; }
        };
        //-----------------------------------------------------------------------------
        /// tetrahedron triangle
        class Triangle : public ITetrahedralVolume::Triangle
        {
        public:
            /**
             */
            Triangle(hfaceid_t _hfaceID, IMassPoints::MassPoint * _n0, IMassPoints::MassPoint * _n1, IMassPoints::MassPoint * _n2, bool _boundary)
                : ITetrahedralVolume::Triangle(_hfaceID, _n0, _n1, _n2, _boundary)
                    { }
        };
        //-----------------------------------------------------------------------------
    public:
        // the structure's container types
        typedef ArrayList<NodeTraits> NodeArrayList;
        typedef ArrayList<nodeid_t>   NodeIndexArrayList;
        typedef ArrayList<hfaceid_t>  HFaceIndexArrayList;
        ///
        enum { OHF_NONE = (hfaceid_t)-1 };
    private:
        ///
        typedef HashContainer<nodeid_t, uint32_t>   NodeVertexMap;
        typedef MassPointMap   NodeDataContainer;       
        ///
        typedef EdgeMap EdgeContainer;
        typedef TriangleMap TriContainer;
        typedef TetrahedronMap TetraContainer;
        ///
        typedef VertexArray BoundaryVertexContainer;
        typedef FaceMap BoundaryFaceContainer;        
    private:   
        /**
         * geometry (and possibly others, e.g., (u,v) tex. coords) associated to each of all geometry vertices this container forms the basic level of the structure's structure
         * @remarks: contains #vertices instances of VertexDataClass
         */
        NodeArrayList mNodeArrayList;
        /**
         * gemoetry half-face container, i.e., indices pointing to the vertex data container to its corresponding apex
         * @remarks: contains 4 * #tetrahedrons indices - implements CHF level 0 (i.e., 4 consecutive half-faces represented by its apexes form one tetrahedron)
         */
        NodeIndexArrayList mHFaceArrayList;
        /**
         * contains opposite half-face indices
         * @remarks: implements CHF level 1
         */
        HFaceIndexArrayList mOppositeHFaceArrayList;
        ///
        NodeDataContainer mNodeDataContainer;
        ///
        EdgeContainer   mEdgeContainer;
        TriContainer    mTriContainer;
        TetraContainer  mTetraContainer;
        ///
        BoundaryVertexContainer mBoundaryVertexContainer;
        BoundaryFaceContainer   mBoundaryFaceContainer;
        NodeVertexMap           mNodeVertexMap;
        bool                    mBoundaryMeshTopologyNeedsUpdate;
        bool                    mBoundaryMeshGeometryNeedsUpdate;
		// pointer to the parent simulation object 
		SimObject * mParentSimObject;

    public:

        //-----------------------------------------------------------------------------
        // Constructors & destructor
        //-----------------------------------------------------------------------------        

        TetraMesh_ModelStructure();                
        virtual ~TetraMesh_ModelStructure();

        //-----------------------------------------------------------------------------
        // IComponent methods
        //-----------------------------------------------------------------------------

        virtual String getDescription() const;        

        //-----------------------------------------------------------------------------
        // ISimObjectComponent methods
        //-----------------------------------------------------------------------------

		virtual void initialize(SimObject * _parentSimObject);
        virtual SimObject * getParentSimObject()
				{ return mParentSimObject; }
        virtual const SimObject * getParentSimObject() const
				{ return mParentSimObject; }

        //-----------------------------------------------------------------------------
        // ComModelStructure methods
        //-----------------------------------------------------------------------------

        virtual void translate(const Vector3 & _trans);
        virtual void rotate(const Vector3 & _axis, real_t _radians);
        virtual void scale(const Vector3 & _scale);

        virtual bool isMassPointsInterfaceSupported()
                { return true; }
        virtual bool isTetrahedralVolumeInterfaceSupported()
                { return true; }
        virtual bool isBoundaryMeshInterfaceSupported()
                { return true; }
        
        virtual IMassPoints * getMassPointsInterface()
                { return this; }                       
        virtual const IMassPoints * getMassPointsInterface() const
                { return this; }                       
        virtual ITetrahedralVolume * getTetrahedralVolumeInterface()
                { return this; }        
        virtual const ITetrahedralVolume * getTetrahedralVolumeInterface() const
                { return this; }        
        virtual IBoundaryMesh * getBoundaryMeshInterface()
                { return this; }
        virtual const IBoundaryMesh * getBoundaryMeshInterface() const
                { return this; }

        //-----------------------------------------------------------------------------
        // IMassPoints
        //-----------------------------------------------------------------------------        
        
        virtual MassPoint::id_t createMassPoints(uint32_t count);
        virtual MassPointMap::Iterator massPointIterator();
        virtual MassPointMap::ConstIterator massPointIterator() const;
        virtual MassPointMap::Reader massPointReader();
        virtual const MassPointMap::Reader massPointReader() const;
        virtual void prepareForPointRendering();
        virtual MassPoint::id_t getNearestMassPointId(const Vector3 & _pos);
    
        //-----------------------------------------------------------------------------
        // ITetrahedralVolume
        //-----------------------------------------------------------------------------        
        
		virtual Tetrahedron::id_t createTetrahedron(IMassPoints::MassPoint::id_t _mp1, IMassPoints::MassPoint::id_t _mp2, 
			IMassPoints::MassPoint::id_t _mp3, IMassPoints::MassPoint::id_t _mp4);
		virtual void destroyTetrahedron(Tetrahedron::id_t _tetraID);
        virtual void subdivideTetrahedron(Tetrahedron::id_t _tetraID, const Vector3 & _point);
        virtual void subdivideEdge(Edge::id_t _edgeID, const Vector3 & _point);
        virtual void subdivideTriangle(Triangle::id_t _triID, const Vector3 & _point);
        virtual void collapseEdge(Edge::id_t _edgeID);        
        virtual EdgeMap::Iterator edgeIterator();
        virtual EdgeMap::ConstIterator edgeIterator() const;
        virtual EdgeMap::Reader edgeReader();
        virtual const EdgeMap::Reader edgeReader() const;
        virtual TriangleMap::Iterator triangleIterator();
        virtual TriangleMap::ConstIterator triangleIterator() const;
        virtual TriangleMap::Reader triangleReader();
        virtual const TriangleMap::Reader triangleReader() const;
        virtual TetrahedronMap::Iterator tetrahedronIterator();
        virtual TetrahedronMap::ConstIterator tetrahedronIterator() const;
        virtual TetrahedronMap::Reader tetrahedronReader();
        virtual const TetrahedronMap::Reader tetrahedronReader() const;
        virtual void prepareForVolumeRendering();

        //-----------------------------------------------------------------------------
        // IBoundaryMesh
        //-----------------------------------------------------------------------------        
        
        virtual void generateFromMassPoints();
        virtual void generateFromTetrahedralVolume();
        virtual uint32_t createVertex(const Vector3 & _position, const Vector3 & _normal, real_t _u, real_t _v);
		virtual Face::id_t createFace(uint32_t  _v0, uint32_t  _v1, uint32_t _v2);
        virtual VertexArray::Iterator vertexIterator();
        virtual VertexArray::ConstIterator vertexIterator() const;
        virtual VertexArray::Reader vertexReader();
        virtual const VertexArray::Reader vertexReader() const;
        virtual FaceMap::Iterator faceIterator();
        virtual FaceMap::ConstIterator faceIterator() const;
        virtual FaceMap::Reader faceReader();
        virtual const FaceMap::Reader faceReader() const;
        virtual void prepareForRendering();

        //-----------------------------------------------------------------------------
        // Other methods
        //-----------------------------------------------------------------------------
        
        /** Adds new vertices into the vertex geometry container.
            @return: Returns ID that was assigned to the first added vertex.
            */
        nodeid_t addNodes(uint32_t nodeCount);        
        
        /**
        */
        uint32_t getNodeCount() const 
                { return mNodeArrayList.getElementCount(); }        
                
        /**
        */
        nodeid_t getNodeIndexID(uint32_t nodeIndex) const 
                { return nodeIndex; }        
                
        /** 
         * Returns the geometry data associated with the geometry structure's vertex.
         * @param: vertexID
         * @return:
         */
        NodeTraits * getNode(nodeid_t nodeID) 
                { return mNodeArrayList.getElementPtr(nodeID); }        
                
        /** Returns the reference to the const vertex geometry list.
         */
        const NodeArrayList & getNodeArrayList() const 
                { return mNodeArrayList; }        

        /**
         * Removes tetrahedron given by its ID.
         * @param:  tetraID
         * @remark: The tetrahedron with the given tetraID must exists in the structure.
         */
        void removeTetra(tetraid_t tetraID);        
        
        /**
        */
        uint32_t getTetraCount() const 
                { return mHFaceArrayList.getElementCount() / 4; }        

        /**
        */
        tetraid_t getTetraIndexID(uint32_t tetraIndex) const 
                { return tetraIndex; }        

        /**
        */
        void getTetraNodeIDs(tetraid_t tetraID, nodeid_t *n1, nodeid_t *n2, nodeid_t *n3, nodeid_t *n4);        

        /**
        */
        hfaceid_t getHFaceIndexID(uint32_t hfaceIndex) const 
                { return hfaceIndex; }        

        /**
        */
        void getHFaceNodeIDs(hfaceid_t hfaceID, nodeid_t * n1, nodeid_t * n2, nodeid_t * n3);        

        /**
        */
        const NodeIndexArrayList & getOppositeHFaceArrayList() const 
                { return mOppositeHFaceArrayList; }

    private:        

        /**
        */
        void _addTri(hfaceid_t _hfaceID, nodeid_t _n1, nodeid_t _n2, nodeid_t _n3);        

        /**
        */
        void _addEdge(nodeid_t _n1, nodeid_t _n2);        

        /**
        */
        uint32_t _hashNodeTriple(nodeid_t n1, nodeid_t n2, nodeid_t n3);        

        /**
        */
        void _checkNodeTripleHash(uint32_t hash, hfaceid_t oppHFaceID, hfaceid_t hfaceID);        

        /**
        */
        hfaceid_t _tetraToHFaceID(tetraid_t tetraID, hfaceid_t hfaceID) 
                { return tetraID * 4 + hfaceID; }        
        /**
        */
        tetraid_t _hfaceToTetraID(hfaceid_t hfaceID) 
                { return static_cast<tetraid_t>(floor(static_cast<float>(hfaceID) / 4.0f)); }        
        /**
        */
        hfaceid_t _firstHFaceID(hfaceid_t hfaceID) 
                { return _tetraToHFaceID(_hfaceToTetraID(hfaceID), 0); }
    };
}
//===========================================================================================
#endif // __dylab_TetraMesh_ModelStructure_h__